package com.fumasoft.dynamic.utils;

import com.mysql.cj.util.StringUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 基于Java8的时间工具类.
 *
 * @Author: jingchen
 * @Date: 2025/08/30
 */
public class DateUtil {

    /**
     * 日志.
     */
    public static Logger logger = LoggerFactory.getLogger(DateUtil.class);

    /**
     * 例如:2018-12-28.
     */
    public static final String DATE = "yyyy-MM-dd";

    /**
     * 例如:2018-12-28.
     */
    public static final String DATE_CN = "yyyy年MM月dd日";

    /**
     * 例如:2018-12-28 10:00:00.
     */
    public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";

    /**
     * 例如:10:00:00.
     */
    public static final String TIME = "HHmmss";

    /**
     * 例如:10:00.
     */
    public static final String TIME_WITHOUT_SECOND = "HH:mm";

    /**
     * 例如:2018-12-28 10:00.
     */
    public static final String DATE_TIME_WITHOUT_SECONDS = "yyyy-MM-dd HH:mm";

    /**
     * 1 second = 1000 milliseconds.
     */
    public static final long SECONDS_IN_MILLI = 1000;

    /**
     * 1 minute = 60 seconds.
     */
    public static final long MINUTES_IN_MILLI = SECONDS_IN_MILLI * 60;

    /**
     * 1 hour = 60 x 60 = 3600.
     */
    public static final long HOURS_IN_MILLI = MINUTES_IN_MILLI * 60;

    /**
     * 1 day = 3600 x 24 = 86400.
     */
    public static final long DAYS_IN_MILLI = HOURS_IN_MILLI * 24;

    /**
     * 默认的日期长度.
     */
    private static final int YEAR_LENGTH = 4;

    /**
     * 默认的开始时间.
     */
    private static final int END_HOUR = 23;

    /**
     * 默认的开始时间.
     */
    private static final int END_MINUTE = 59;

    /**
     * 默认的开始时间.
     */
    private static final int END_SECOND = 59;

    /**
     * 默认的日期格式.
     */
    private static final int END_NANO = 999;

    /**
     * 默认的日期格式.
     */
    private static final int DECEMBER = 12;

    /**
     * 默认的日期格式.
     */
    private static final int MONTH_START = 5;

    /**
     * 默认的日期格式.
     */
    private static final int MONTH_END = 7;

    /**
     * 默认的日期格式.
     */
    private static final int DAY_START = 8;

    /**
     * 默认的日期格式.
     */
    private static final int DAY_END = 10;

    /**
     * 默认的日期格式.
     */
    private static final int DATE_LENGTH_LONG = 19;

    /**
     * 默认的日期格式.
     */
    private static final int HOURS_PER_DAY = 24;

    /**
     * 默认的日期格式.
     */
    public static final SimpleDateFormat DATE_FORMAT =  new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 默认的日期时间格式.
     */
    public static final String[] PARSE_PATTERNS = {"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy-MM-dd HH:mm", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd", "yyyy/MM/dd HH:mm:"};

    /**
     * 获取当前时间.
     *
     * @return 当前时间
     */
    public static Date parseDate(String str) {
        if (str == null) {
            return null;
        }
        try {
            return DateUtils.parseDate(str, PARSE_PATTERNS);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取年.
     *
     * @return 年
     */
    public static int getYear() {
        LocalTime localTime = LocalTime.now();
        return localTime.get(ChronoField.YEAR);
    }

    /**
     * 获取指定日期是周几.
     *
     * @param date  date
     * @return  int
     */
    public static int getYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.YEAR);
    }

    /**
     * 获取月份.
     *
     * @return 月份
     */
    public static int getMonth() {
        LocalTime localTime = LocalTime.now();
        return localTime.get(ChronoField.MONTH_OF_YEAR);
    }

    /**
     * 获取某月的第几天.
     *
     * @return 几号
     */
    public static int getMonthOfDay() {
        LocalTime localTime = LocalTime.now();
        return localTime.get(ChronoField.DAY_OF_MONTH);
    }

    /**
     * 获取当前时间.
     *
     * @param year  年
     * @return  年
     */
    public static String subYear(String year) {
        if (Objects.isNull(year)) {
            return "";
        }
        if (year.length() >= YEAR_LENGTH) {
            return year.substring(0, YEAR_LENGTH);
        }
        return year;
    }

    /**
     * 格式化日期为字符串.
     *
     * @param date    date
     * @param pattern 格式
     * @return 日期字符串
     */
    public static String format(Date date, String pattern) {

        Instant instant = date.toInstant();

        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 格式化日期为字符串.
     *
     * @param date    date
     * @param pattern 格式
     * @return 日期字符串
     */
    public static String format(LocalDateTime date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 格式化日期为字符串.
     *
     * @param date    date
     * @param pattern 格式
     * @return 日期字符串
     */
    public static String format(LocalDate date, String pattern) {
        return date.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 解析字符串日期为Date.
     *
     * @param dateStr 日期字符串
     * @param pattern 格式
     * @return Date
     */
    public static Date parse(String dateStr, String pattern) {

        LocalDateTime localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
        Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
        return Date.from(instant);
    }

    /**
     * 为Date增加分钟,减传负数.
     *
     * @param date        日期
     * @param plusMinutes 要增加的分钟数
     * @return 新的日期
     */
    public static Date addMinutes(Date date, Long plusMinutes) {
        LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        LocalDateTime newDateTime = dateTime.plusMinutes(plusMinutes);
        return Date.from(newDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 增加时间.
     *
     * @param date date
     * @param hour 要增加的小时数
     * @return new date
     */
    public static Date addHour(Date date, Long hour) {
        LocalDateTime dateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        LocalDateTime localDateTime = dateTime.plusHours(hour);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当天的起始时间.
     *
     * @return 返回当天的起始时间.
     */
    public static Date getStartTime() {
        LocalDateTime now = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0);
        return localDateTime2Date(now);
    }

    /**
     * 获取当天的结束时间.
     *
     * @return 返回当天的结束时间.
     */
    public static Date getEndTime() {
        LocalDateTime now = LocalDateTime.now().withHour(END_HOUR).withMinute(END_MINUTE).withSecond(END_MINUTE).withNano(END_NANO);
        return localDateTime2Date(now);
    }

    /**
     * 获取当天的结束时间.
     *
     * @return 返回当天的结束时间.
     */
    public static LocalDateTime getLocalDateTimeEndTime() {
        return LocalDateTime.now().withHour(END_NANO).withMinute(END_MINUTE).withSecond(END_MINUTE).withNano(END_NANO);
    }

    /**
     * 获得某天最大时间 2017-10-15 23:59:59.
     *
     * @return 2017-10-15 23:59:59
     */
    public static Date getEndOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获得某天最小时间 2017-10-15 00:00:00.
     *
     * @return 2017-10-15 00:00:00
     */
    public static Date getStartOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
        return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 减月份.
     *
     * @param monthsToSubtract 月份
     * @return Date
     */
    public static Date minusMonths(long monthsToSubtract) {
        LocalDate localDate = LocalDate.now().minusMonths(monthsToSubtract);

        return localDate2Date(localDate);
    }

    /**
     * LocalDate类型转为Date.
     *
     * @param localDate LocalDate object
     * @return Date object
     */
    public static Date localDate2Date(LocalDate localDate) {

        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());

        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * LocalDateTime类型转为Date.
     *
     * @param localDateTime LocalDateTime object
     * @return Date object
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 查询当前年的第一天.
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20190101
     */
    public static String getFirstDayOfCurrentYear(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now().withMonth(1).withDayOfMonth(1);

        if (StringUtils.isNullOrEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * 查询前一年最后一个月第一天.
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20190101
     */
    public static String getLastMonthFirstDayOfPreviousYear(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now().minusYears(1L).withMonth(DECEMBER).withDayOfMonth(1);

        if (StringUtils.isNullOrEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * 查询前一年最后一个月第一天.
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20190101
     */
    public static String getLastMonthLastDayOfPreviousYear(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now().minusYears(1L).with(TemporalAdjusters.lastDayOfYear());

        if (StringUtils.isNullOrEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * 获取当前日期.
     *
     * @param pattern 格式，默认格式yyyyMMdd
     * @return 20190101
     */
    public static String getCurrentDay(String pattern) {
        LocalDateTime localDateTime = LocalDateTime.now();

        if (StringUtils.isNullOrEmpty(pattern)) {
            pattern = "yyyyMMdd";
        }

        return format(localDateTime2Date(localDateTime), pattern);
    }

    /**
     * LocalDate类型转为Date.
     *
     * @param date LocalDate object
     * @return Date object
     */
    public static LocalDate dateToLocalDate(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * LocalDateTime类型转为Date.
     *
     * @param date LocalDateTime object
     * @return LocalDateTime object
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        if (null == date) {
            return null;
        }
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 不确定的时间格式，统一转换 yyyy-MM-ddddddd.
     */
    public static String converDateToString(String date) {
        if ("".equals(date) || null == date || (date.length() != DAY_END && date.length() != DATE_LENGTH_LONG && date.length() != END_HOUR)) {
            return getCurrentDay(DATE);
        }
        String format = date.substring(0, YEAR_LENGTH) + "-" + date.substring(MONTH_START, MONTH_END) + "-" + date.substring(DAY_START, DAY_END);
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);
        try {
            sdf.parse(format);
        } catch (ParseException e) {
            return "";
        }
        return format;
    }

    /**
     * 不确定的时间格式，统一转换 yyyy-MM-ddddddd.
     */
    public static Date converDateToDate(String date) {
        if (null == date || date.length() != DAY_END) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(DATE);

        try {
            return sdf.parse(date.substring(0, YEAR_LENGTH) + "-" + date.substring(MONTH_START, MONTH_END) + "-" + date.substring(DAY_START, DAY_END));
        } catch (ParseException e) {
            logger.error("时间格式不匹配，转化失败，详情如下,{}", e.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 计算指定时间 的差值   1.
     *
     * @param  startDate  10/10/2013 11:30:10
     * @param  endDate    13/10/2013 20:35:55
     * @return 3 天, 9 小时, 5 分钟, 45 秒
     */
    public static String printDifference(Date startDate, Date endDate) {
        if (null == startDate || null == endDate) {
            return null;
        }

        long different = endDate.getTime() - startDate.getTime();

        different = different % DAYS_IN_MILLI;

        long elapsedHours = different / HOURS_IN_MILLI;
        different = different % HOURS_IN_MILLI;

        long elapsedMinutes = different / MINUTES_IN_MILLI;
        different = different % MINUTES_IN_MILLI;

        long elapsedSeconds = different / SECONDS_IN_MILLI;

        long elapsedDays = different / DAYS_IN_MILLI;

        return String.format("%d 天 %d 小时 %d 分钟 %d 秒%n", elapsedDays, elapsedHours, elapsedMinutes, elapsedSeconds);

    }

    /**
     *  截取日期.
     *
     * @author: gwh
     * @date: 2022/6/10 10:21
     * @param: [strDate, start, end] strDate日期，start截取开始，end截取结束
     * @return: java.lang.String
     **/
    public static String subDate(String strDate, int start, int end) {
        if (strDate != null && !strDate.equals("")) {
            return null;
        }
        if (strDate.length() < start) {
            return null;
        }
        return strDate.substring(start, end);
    }

    /**
     * 获取过去第几天的日期.
     *
     * @author: gwh
     * @param past  past
     * @return  String
     */
    public static String getPastDate(int past) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
        Date today = calendar.getTime();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String result = format.format(today);
        return result;
    }

    /**
     * 获取指定日期是周几.
     *
     * @param date  date
     * @return  int
     */
    public static int getDayOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取指定日期是周几.
     *
     * @param date  date
     * @return  int
     */
    public static int getmonthOfYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.MONTH);
    }

    /**
     * JDK 8计算两个时间相差的天数，支持跨月、跨年.
     *
     * @param startTimeStamp 开始时间戳
     * @param endTimeStamp 结束时间戳
     * @return 相距天数，若开始时间大于结束时间，则返回对应复数
     */
    public static long diffDays(long startTimeStamp, long endTimeStamp) {
        LocalDate startTime = Instant.ofEpochMilli(startTimeStamp).atZone(ZoneOffset.ofHours(DAY_START)).toLocalDate();
        LocalDate endTime = Instant.ofEpochMilli(endTimeStamp).atZone(ZoneOffset.ofHours(DAY_START)).toLocalDate();
        return ChronoUnit.DAYS.between(startTime, endTime);
    }

    /**
     * 获取当前时间.
     *
     * @return  String
     */
    public static String getNowTime() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(DATE_TIME));
    }

    /**
     * 获取当前时区的时间 yyyy-mm-dd hh:mm:ss+|-hh:mm", for example, "2019-01-01 12:32:45-08:00.
     *
     * @author: gwh
     * @date: 2022/11/16 14:07
     * @param: []
     * @return: java.lang.String
     **/
    public static String  getZoneTime() {
        TimeZone zone = TimeZone.getDefault();
        ZonedDateTime zoneNow = ZonedDateTime.now(TimeZone.getTimeZone(zone.getID()).toZoneId());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
        //时区
        String offset = zoneNow.getOffset().toString().replace("+", "");
        String nowTime = zoneNow.format(formatter);
        return nowTime + "+" + offset;
    }

    /**
     * 获取cron表达式.
     *
     * @param date  date
     * @return  String
     */
    public static String getCronExpression(Date date) {
        SimpleDateFormat format = new SimpleDateFormat("ss mm HH dd MM ? yyyy");
        return format.format(date);
    }

    /**
     * 计算两个时间相差天数.
     *
     * @param createTime 开始时间
     * @param endTime 结束时间
     * @return 返回天数
     */
    public static Long calculateDuration(Date createTime, Date endTime) {
        Instant createInstant = createTime.toInstant();
        Instant currentInstant = endTime.toInstant();

        LocalDateTime createDateTime = createInstant.atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime currentDateTime = currentInstant.atZone(ZoneId.systemDefault()).toLocalDateTime();

        Duration duration = Duration.between(createDateTime, currentDateTime);

        long totalHours = duration.toHours();
        long days = totalHours / HOURS_PER_DAY;
        long hours = totalHours % HOURS_PER_DAY;
        return days;
    }

    /**
     * 日期英文格式翻译.
     *
     * @param date 日期
     * @param language 语言 zh 中文 en英文
     * @return 翻译后的日期格式
     */
    public static String translateDate(String date, String language) {
        try {
            // 指定中文日期格式
            DateTimeFormatter chineseFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            // 解析中文日期字符串为LocalDate对象
            LocalDate chineseDate = LocalDate.parse(date, chineseFormatter);
            // 根据指定的语言创建Locale对象
            Locale targetLocale = new Locale(language);
            // 根据目标Locale创建日期格式化器
            DateTimeFormatter targetFormatter = DateTimeFormatter.ofPattern("MMMM dd, yyyy", targetLocale);
            // 格式化日期为目标语言
            return  targetFormatter.format(chineseDate);
        } catch (Exception e) {
            return date; // 解析失败，返回原始日期
        }
    }
}
